package com.taylor.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

/**
 * @Desc : NIO服务端
 * 1 当客户端连接时，会通过 ServerSocketChannel 得到 SocketChannel。
 * 2 Selector 进行监听 select 方法，返回有事件发生的通道的个数。
 * 3 将 socketChannel 注册到 Selector 上，register(Selector sel, int ops)，一个 Selector 上可以注册多个 SocketChannel。
 * 4 注册后返回一个 SelectionKey，会和该 Selector 关联（集合）。
 * 5 进一步得到各个 SelectionKey（有事件发生）。
 * 6 在通过 SelectionKey 反向获取 SocketChannel，方法 channel()。
 * 7 可以通过得到的 channel，完成业务处理。
 * @Author ： taylor
 * @Date ：2021/6/26 21:47
 */
public class NIOServer {

    public static void main(String[] args) {

        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            ServerSocket serverSocket = serverSocketChannel.socket();
            //serverSocket绑定地址
            serverSocket.bind(new InetSocketAddress(8888));
            //socketChannel 设置为非阻塞
            serverSocketChannel.configureBlocking(false);

            //socketChannel注册到selector上
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //等待客户端连接
            while (true){

                //监听事件 1m无事件返回
                if (selector.select(1000)==0){
                    System.out.println(new Date()+" 等待连接");
                    continue;
                }
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
                while (keyIterator.hasNext()){
                    SelectionKey selectionKey = keyIterator.next();
                    /**
                     * 获取一个新连接，则生成一个新的socketChannel
                     */
                    if (selectionKey.isAcceptable()){
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        System.out.println("客户端新连接 "+socketChannel.hashCode());

                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    }
                    /**
                     * 发生读取事件
                     */
                    if (selectionKey.isReadable()){

                        //通过key获取对应的channel
                        SocketChannel channel = (SocketChannel)selectionKey.channel();
                        ByteBuffer buffer = (ByteBuffer)selectionKey.attachment();
                        channel.read(buffer);
                        System.out.println("从客户端获取数据："+new String(buffer.array()));
                    }

                    //防止重复 从集合中移除key
                    selectionKeys.remove(selectionKey);

                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
